// FBXImporter.cpp
#include "FBXImporter.h"

namespace ANvDbg
{
    void FBXImporter::Test()
    {
        FbxManager* fbx_manager = FbxManager::Create();
        FbxIOSettings* fbx_iosetting = FbxIOSettings::Create(fbx_manager, IOSROOT);
        FbxImporter* fbx_importer = FbxImporter::Create(fbx_manager, "");

        fbx_manager->SetIOSettings(fbx_iosetting);

        fbx_importer->Initialize("media/model/cube.fbx", -1, fbx_manager->GetIOSettings());

        FbxScene* fbx_scene = FbxScene::Create(fbx_manager, "CubeScene");
        fbx_importer->Import(fbx_scene);
        fbx_importer->Destroy();

        FbxNode* root_node = fbx_scene->GetRootNode();

        printf("animation stack count is %d.\n", fbx_scene->GetSrcObjectCount<FbxAnimStack>());
        for (int i = 0; i < fbx_scene->GetSrcObjectCount<FbxAnimStack>(); ++i)
        {
            FbxAnimStack* fbx_animstack = fbx_scene->GetSrcObject<FbxAnimStack>(i);
            printf("stack %d : %s has animation layer count %d.\n",
                i, fbx_animstack->GetName(), fbx_animstack->GetMemberCount<FbxAnimLayer>());
            for (int j = 0; j < fbx_animstack->GetMemberCount<FbxAnimLayer>(); ++j)
            {
                FbxAnimLayer* fbx_animlayer = fbx_animstack->GetMember<FbxAnimLayer>(j);
                printf("layer %d : %s has animation layer count %d.\n",
                    j, fbx_animlayer->GetName(), fbx_animstack->GetMemberCount<FbxAnimLayer>());

                ReadCurve(root_node, fbx_animlayer);
            }
        }

        DumpNode(root_node);

        fbx_manager->Destroy();
    }

    void FBXImporter::DumpNode(FbxNode* node)
    {
        printf("node : %s.\n", node->GetName());
        for (int i = 0; i < node->GetNodeAttributeCount(); ++i)
        {
            FbxNodeAttribute* attr_node = node->GetNodeAttributeByIndex(i);
            if (attr_node != nullptr)
            {
                if (attr_node->GetAttributeType() == FbxNodeAttribute::eMesh)
                {
                    printf("detect a mesh attribute node.\n");

                    FbxMesh* fbx_mesh = node->GetMesh();
                    printf("vertex count is : %d.\n", fbx_mesh->GetControlPointsCount());
                    if (fbx_mesh != nullptr)
                    {
                        for (int index = 0; index < fbx_mesh->GetPolygonCount(); ++index)
                        {
                            printf("triangle %d : %d index count.\n", index, fbx_mesh->GetPolygonSize(index));
                        }

                        for (int index = 0; index < fbx_mesh->GetLayerCount(); ++index)
                        { // Normal/UV/Texture/Tangent
                            FbxLayer* fbx_layer = fbx_mesh->GetLayer(index);
                            if (fbx_layer == nullptr)
                            {
                                continue;
                            }

                            //FbxLayerElementNormal* layer_normal = fbx_layer->GetLayerElementOfType(FbxLayerElement::eNormal);
                            FbxLayerElementNormal* layer_normal = fbx_layer->GetNormals();
                            if (layer_normal == nullptr)
                            {
                                continue;
                            }

                            switch (layer_normal->GetReferenceMode())
                            {
                            case FbxLayerElement::EReferenceMode::eDirect:
                            {
                                auto& direct_array = layer_normal->GetDirectArray();
                                float x = direct_array.GetAt(0).mData[0];
                                float y = direct_array.GetAt(0).mData[1];
                                float z = direct_array.GetAt(0).mData[2];
                                float w = direct_array.GetAt(0).mData[3];

                                printf("eDirect, array count : %d.\n", direct_array.GetCount());

                                break;
                            }
                            case FbxLayerElement::EReferenceMode::eIndexToDirect:
                            {
                                auto& direct_array = layer_normal->GetDirectArray();
                                auto& index_array = layer_normal->GetIndexArray();
                                int real_index = index_array.GetAt(0);
                                float x = direct_array.GetAt(real_index).mData[0];
                                float y = direct_array.GetAt(real_index).mData[1];
                                float z = direct_array.GetAt(real_index).mData[2];
                                float w = direct_array.GetAt(real_index).mData[3];

                                printf("eIndexToDirect, array count : %d.\n", direct_array.GetCount());

                                break;
                            }
                            case FbxLayerElement::EReferenceMode::eIndex:
                            {
                                break;
                            }
                            default:
                                break;
                            }
                        }
                    }
                }
            }

            printf("material count : %d.\n", node->GetMaterialCount());
            for (int j = 0; j < node->GetMaterialCount(); ++j)
            { // material : lambert, phong, cg
                FbxSurfaceMaterial* fbx_material = node->GetMaterial(j);
                if (fbx_material->GetClassId() == FbxSurfaceLambert::ClassId)
                {
                    printf("%d lambert material.\n", j);
                }
                else if (fbx_material->GetClassId() == FbxSurfacePhong::ClassId)
                {
                    printf("%d phong material : %s.\n", j, fbx_material->GetName());

                    FbxProperty fbx_property = fbx_material->FindProperty(FbxSurfaceMaterial::sDiffuse);
                    if (fbx_property.IsValid())
                    {
                        FbxTexture* texture = fbx_property.GetSrcObject<FbxTexture>();

                        printf("material texture name : %s, texture count : %d.\n",
                            texture->GetName(), fbx_property.GetSrcObjectCount(FbxTexture::ClassId));
                    }
                }
            }
        }

        int nChildCount = node->GetChildCount();
        for (int i = 0; i < node->GetChildCount(); ++i)
        {
            DumpNode(node->GetChild(i));
        }
    }

    void FBXImporter::ReadCurve(FbxNode* fbx_node, FbxAnimLayer* fbx_animlayer)
    {
        FbxAnimCurve* fbx_animcurve = fbx_node->LclTranslation.GetCurve(fbx_animlayer);
        if (fbx_animcurve != nullptr)
        {
            printf("xxxxxx");
        }

        for (int i = 0; i < fbx_node->GetChildCount(); ++i)
        {
            ReadCurve(fbx_node->GetChild(i), fbx_animlayer);
        }
    }
}
